//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------


using System;
using System.Web;
using System.Collections;
using CommunityServer;
using CommunityServer.Blogs.Components;
using CommunityServer.Components;
using CookComputing.XmlRpc;

namespace CommunityServer.Blogs.Components
{
	/// <summary>
	/// Summary description for MetaWeblog.
	/// </summary>
	public class MetaWeblog : XmlRpcService, IMetaWeblog
	{
		public MetaWeblog()
		{
			
		}


		#region Structs

		public struct BlogInfo
		{
			public string blogid;
			public string url;
			public string blogName;
		}

		public struct Category
		{
			public string categoryId;
			public string categoryName;
		}

		[Serializable]
		public struct CategoryInfo
		{
			public string description;
			public string htmlUrl;
			public string rssUrl;
			public string title;
			public string categoryid;
		}

		[XmlRpcMissingMapping(MappingAction.Ignore)]
		public struct Enclosure
		{
			public int length;
			public string type;
			public string url;
		}

		[XmlRpcMissingMapping(MappingAction.Ignore)]
		public struct Post
		{
			[XmlRpcMissingMapping(MappingAction.Error)]
			[XmlRpcMember(Description="Required when posting.")]
			public DateTime dateCreated;
			[XmlRpcMissingMapping(MappingAction.Error)]
			[XmlRpcMember(Description="Required when posting.")]
			public string description;
			[XmlRpcMissingMapping(MappingAction.Error)]
			[XmlRpcMember(Description="Required when posting.")]
			public string title;

			public string[] categories;
			public Enclosure enclosure;
			public string link;
			public string permalink;
			[XmlRpcMember(
				 Description="Not required when posting. Depending on server may "
				 + "be either string or integer. "
				 + "Use Convert.ToInt32(postid) to treat as integer or "
				 + "Convert.ToString(postid) to treat as string")]
			public object postid;       
			public Source source;
			public string userid;

			//public string mt_excerpt;
		}


		[XmlRpcMissingMapping(MappingAction.Ignore)]
		public struct Source
		{
			public string name;
			public string url;
		}

		public struct UserInfo
		{
			public string userid;
			public string firstname;
			public string lastname;
			public string nickname;
			public string email;
			public string url;
		}
		
		#endregion

		#region MetaWeblog API Members

		public string newPost(string blogid, string username, string password, MetaWeblog.Post post, bool publish)
		{
			if(ValidateUser(username,password))
			{
				CSContext cntx = CSContext.Current;
				Weblog weblog = Weblogs.GetWeblog(blogid, true);
				Permissions.AccessCheck(weblog, Permission.Post, cntx.User);

				WeblogPost postToAdd = new WeblogPost();
				postToAdd.BlogPostType = BlogPostType.Post;
				postToAdd.SectionID = weblog.SectionID;

				// Set Default Values
				postToAdd.PostConfig = weblog.DefaultPostConfig;
				postToAdd.EnableRatings = weblog.EnableRatingsDefault;
				postToAdd.EnableTrackBacks = weblog.EnableTrackbacksDefault;
				postToAdd.EnableAllOwnerNotification = weblog.EnableAllOwnerNotification;
				postToAdd.FeedbackNotificationType = weblog.FeedbackNotificationType;
				postToAdd.ModerationType = weblog.ModerationTypeDefault;
				postToAdd.EnableCrossPosting = weblog.EnableCrossPostingDefault;

				postToAdd.IsApproved = publish;
				postToAdd.Body = post.description;
				postToAdd.Subject = post.title;
				postToAdd.Categories = post.categories;
				
				// Get UserTime safely (some clients pass in a DateTime that is not valid)
				try
				{
					if (post.dateCreated != DateTime.MinValue)
						postToAdd.UserTime = post.dateCreated;
					else
						postToAdd.UserTime = CommunityServer.Components.UserTime.CurrentUserTime;
				}
				catch { postToAdd.UserTime = CommunityServer.Components.UserTime.CurrentUserTime; }
				
				postToAdd.PostDate = UserTime.ConvertToServerTime(postToAdd.UserTime);
				
				int postID = -1;
				BlogPostResults result = WeblogPosts.Add(postToAdd, cntx.User, out postID);

				if(postID != -1 && result == BlogPostResults.Success)
					return postID.ToString();	
				else
					throw new XmlRpcFaultException(0,"The post could not be added");
			}


			throw new XmlRpcFaultException(0,"User does not exist");
		}


		public bool editPost(string postid,	string username,string password,Post post,bool publish)
		{
			if(ValidateUser(username,password))
			{

				WeblogPost wp = WeblogPosts.GetPost(Int32.Parse(postid), false, false, false);
				Weblog weblog = Weblogs.GetWeblog(wp.SectionID,true);
				Permissions.AccessCheck(weblog,Permission.Post, CSContext.Current.User);

				wp.Categories = post.categories;
				wp.Body = post.description;
				wp.Subject = post.title;
				wp.IsApproved = publish;
				wp.FormattedBody = null; // This will get reset in the Update method

				// Get UserTime safely (some clients pass in a DateTime that is not valid)
				try
				{
					if (post.dateCreated != DateTime.MinValue)
						wp.UserTime = post.dateCreated;
//					else
//						wp.UserTime = CommunityServer.Components.UserTime.CurrentUserTime;
				}
				catch {  }
				
				wp.PostDate = UserTime.ConvertToServerTime(wp.UserTime);
				
				WeblogPosts.Update(wp);

				return true;
			}

			throw new XmlRpcFaultException(0,"User does not exist");
		}


		public MetaWeblog.Post getPost(string postid,string username,string password)
		{
			if(ValidateUser(username,password))
			{
				WeblogPost wp = WeblogPosts.GetPost(Int32.Parse(postid), false, false, false);
				Weblog weblog = Weblogs.GetWeblog(wp.SectionID,true);
				Permissions.AccessCheck(weblog,Permission.Post, CSContext.Current.User);
				
				return ConvertToPost(wp);
			}

			throw new XmlRpcFaultException(0,"User does not exist");
		}

		
		public MetaWeblog.CategoryInfo[] getCategories(string blogid,string username,string password)
		{
			if(ValidateUser(username,password))
			{
				Weblog weblog = Weblogs.GetWeblog(blogid,true);
				Permissions.AccessCheck(weblog,Permission.Post, CSContext.Current.User);
				ArrayList categories =  PostCategories.GetCategories(weblog.SectionID, true);
				ArrayList al = new ArrayList(categories.Count);
				BlogUrls urls = BlogUrls.Instance();
				foreach(PostCategory pc in categories)
				{
					CategoryInfo ci = new CategoryInfo();
					ci.categoryid = pc.CategoryID.ToString();
					ci.description = pc.Name; //fix issue with w.bloggar using description and not title? 
					ci.title = pc.Name;
					ci.htmlUrl = Globals.FullPath(urls.IndividualCategoryPage(weblog.ApplicationKey, pc.CategoryID));
					ci.rssUrl = Globals.FullPath(urls.Rss(weblog.ApplicationKey,pc.CategoryID));
					al.Add(ci);
				}

				return al.ToArray(typeof(CategoryInfo)) as CategoryInfo[];
			}
			throw new XmlRpcFaultException(0,"User does not exist");
		}


		public MetaWeblog.Post[] getRecentPosts(string blogid,string username,string password,int numberOfPosts)
		{
			if(ValidateUser(username,password))
			{
				Weblog weblog = Weblogs.GetWeblog(blogid, true, false);
				Permissions.AccessCheck(weblog,Permission.Post, CSContext.Current.User);
				
				BlogThreadQuery query = BlogThreadQuery.CreateNewSingleBlogQuery(weblog.SectionID);
				query.BlogPostType = BlogPostType.Post;
				query.PublishedFilter = BlogPostPublishedFilter.All;
				query.PageSize = numberOfPosts;
				query.PageIndex = 0;

				ThreadSet posts = WeblogPosts.GetBlogThreads(query,false);
				ArrayList al = new ArrayList(posts.Threads.Count);
				foreach(WeblogPost p in posts.Threads)
				{
					al.Add(ConvertToPost(p));
				}

				return (Post[])al.ToArray(typeof(Post));

			}
			throw new XmlRpcFaultException(0,"User does not exist");
		}

		
		#endregion

		#region Blogger API Members

		public MetaWeblog.BlogInfo[] getUsersBlogs(string appKey, string username,string password)
		{
			if(ValidateUser(username,password))
			{
				ArrayList blogs = Weblogs.GetWeblogs(true,false,false);
				blogs = Sections.FilterByAccessControl(blogs, Permission.Post, CSContext.Current.User);

				ArrayList al = new ArrayList(blogs.Count);
				foreach(Weblog weblog in blogs)
				{
					BlogInfo bi = new BlogInfo();
					bi.blogid = weblog.ApplicationKey;
					bi.blogName = weblog.Name;
					bi.url = Globals.FullPath(BlogUrls.Instance().HomePage(weblog.ApplicationKey));
                    
					al.Add(bi);
				}

				return (BlogInfo[])al.ToArray(typeof(BlogInfo));
			}
			throw new XmlRpcFaultException(0,"User does not exist");
		}


		public bool deletePost(string appKey,string postid, string username, string password, [XmlRpcParameter(Description="Where applicable, this specifies whether the blog should be republished after the post has been deleted.")] bool publish)
		{
			if(ValidateUser(username,password))
			{
				CSContext cntx = CSContext.Current;
				WeblogPost post = WeblogPosts.GetPost(Int32.Parse(postid), false, false, false);
				Weblog weblog = Weblogs.GetWeblog(post.SectionID);
				Permissions.AccessCheck(weblog,Permission.Post, cntx.User, post);

				WeblogPosts.Delete(post, cntx.User.UserID);
				return true;
			}

			throw new XmlRpcFaultException(0,"User does not exist");
		}

		
		public MetaWeblog.UserInfo getUserInfo(string appKey, string username,string password)
		{
			if(ValidateUser(username, password))
			{
				CSContext cntx = CSContext.Current;
				if (cntx.User != null)
				{
					User user = cntx.User;
					UserInfo ui = new UserInfo();
					ui.userid = user.Username;
					ui.firstname = "";
					ui.lastname = "";

					if (!Globals.IsNullorEmpty(user.Email))
						ui.email = user.Email;
					else
						ui.email = "";

					if ( user.EnableDisplayName && !Globals.IsNullorEmpty(user.DisplayName) )
						ui.nickname = user.DisplayName;
					else
						ui.nickname = "";

					if (!Globals.IsNullorEmpty(user.Profile.WebAddress))
						ui.url = user.Profile.WebAddress;
					else
						ui.url = "";

					return ui;
				}
			}
			throw new XmlRpcFaultException(0,"User does not exist");
		}

		#endregion

		#region Private Helper Methods

		private bool ValidateUser(string username, string password)
		{

			try
			{
				User u = new User();
				u.Username = username;
				u.Password = password;
				CommunityServer.Components.LoginUserStatus status = Users.ValidUser(u);
				if(status == CommunityServer.Components.LoginUserStatus.Success)
				{
					//System.Web.Security.FormsAuthentication.SetAuthCookie(u.Username,false);
					CSContext.Current.User = Users.GetUser(-1,u.Username,false,false);
					return true;
				}

			}
			catch{}

			return false;
		}


		private string[] GetCategories(int postID)
		{
			return null;
		}

		
		private MetaWeblog.Post ConvertToPost(WeblogPost wp)
		{
			MetaWeblog.Post p = new Post();
			p.categories = wp.Categories;
			p.dateCreated = wp.UserTime;
			p.description = wp.Body;
			p.link = BlogUrls.Instance().Post(wp);
			p.permalink = p.link;
			p.postid = wp.PostID.ToString();
			p.title = wp.Subject;
			return p;
		}


		#endregion
	
	}
}

